<%
    KB = 1024
    MB = 1024*1024
    GB = 1024*1024*1024
    start_addr = 0
    def readable_size(value):
        if value > GB:
            return f"{value/GB} GB"
        if value > MB:
            return f"{value/MB} MB"
        if value > KB:
            return f"{value/KB} KB"
        return value

    def not_4k_align(value) -> bool:
        if value & (4096-1):
            return True
        return False

    pci_devices_bundles_cnt = 0
    mem_regions_bundles_cnt = 0
    if ivshmem['isvshmem_bundle']:
        pci_devices_bundles_cnt = 3
        mem_regions_bundles_cnt = 12
    
%>
/*
 * Jailhouse, a Linux-based partitioning hypervisor
 * Root cell configuration for ${name}
 * Created by resource-tool
 */

#include <jailhouse/types.h>
#include <jailhouse/cell-config.h>

struct {
    struct jailhouse_system header;
    __u64 cpus[${len(cpu["bitmap"])}];
    struct jailhouse_memory mem_regions[${len(devices)+len(root_sys_mems)+len(regions)+ivshmem['count']+2 + mem_regions_bundles_cnt}];
    struct jailhouse_irqchip irqchips[${gic_info["gic_int_no_max"] // 128 +1}];
    struct jailhouse_pci_device pci_devices[${1+len(pci_devices) + pci_devices_bundles_cnt}];
} __attribute__((packed)) config = {
    .header = {
        .signature = JAILHOUSE_SYSTEM_SIGNATURE,
        .revision = JAILHOUSE_CONFIG_REVISION,
        .architecture = JAILHOUSE_ARM64,
        .flags = JAILHOUSE_SYS_VIRTUAL_DEBUG_CONSOLE,
        .hypervisor_memory = {
            .phys_start = ${hex(hypervisor["addr"])},
            .size =       ${hex(hypervisor["size"])} // ${readable_size(hypervisor["size"])}
        },
        %if debug_console:  #根据debug_console是否存在来添加
        .debug_console = {
            .address = ${hex(debug_console['addr'])},
            .size = ${hex(debug_console['size'])},
            %if debug_console['type'] == '8250':
            .type = JAILHOUSE_CON_TYPE_8250,
            %else:
            .type = ${debug_console['type']},
            %endif
            .flags = JAILHOUSE_CON_ACCESS_MMIO | JAILHOUSE_CON_REGDIST_4,
        },
        %endif
        .platform_info = {
            .pci_mmconfig_base = ${hex(pci_mmconfig["base"])},
            .pci_mmconfig_end_bus = ${hex(pci_mmconfig["end_bus"])},
            .pci_is_virtual = 1,
            .pci_domain = ${pci_mmconfig["pci_domain"]},

            .arm = {
                .gic_version = ${gic_info["gic_version"]},
                .gicd_base = ${hex(gic_info["gicd_base"])},
                .gicr_base = ${hex(gic_info["gicr_base"])},
                .gicc_base = ${hex(gic_info["gicc_base"])},
                .gich_base = ${hex(gic_info["gich_base"])},
                .gicv_base = ${hex(gic_info["gicv_base"])},
                .maintenance_irq = 25,
            },
        },
        .root_cell = {
            .name = "${name}",
            .cpu_set_size = sizeof(config.cpus),
            .num_memory_regions = ARRAY_SIZE(config.mem_regions),
            .num_irqchips = ARRAY_SIZE(config.irqchips),
            .num_pci_devices = ARRAY_SIZE(config.pci_devices),
            .vpci_irq_base = ${vpci_irq_base},
        },
    },

    .cpus = {
        // CPU count: cpu['count']
        ${', '.join(cpu['bitmap'])}
    },

    .mem_regions = {
        %if ivshmem:
        /* IVSHMEM regions */
        {
            .phys_start = ${hex(ivshmem['phys'])},
            .virt_start = ${hex(ivshmem['virt'])},
            .size       = ${hex(ivshmem['state_size'])},  // ${readable_size(ivshmem['state_size'])}
            .flags      = JAILHOUSE_MEM_READ,
        },
        {
            .phys_start = ${hex(ivshmem['phys']+ivshmem['state_size'])},
            .virt_start = ${hex(ivshmem['virt']+ivshmem['state_size'])},
            .size       = ${hex(ivshmem['rw_size'])},  // ${readable_size(ivshmem['rw_size'])}
            .flags      = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE,
        },
        %for idx in range(ivshmem['count']):
        {
            .phys_start = ${hex(ivshmem['phys']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx)},
            .virt_start = ${hex(ivshmem['virt']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx)},
            .size       = ${hex(ivshmem['out_size'])},  // ${readable_size(ivshmem['out_size'])}
            %if idx == ivshmem['id']:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE,
            %else:
            .flags = JAILHOUSE_MEM_READ,
            %endif
        },
        %endfor
        <%
            start_addr = ivshmem['phys']+ivshmem['state_size']+ivshmem['rw_size'] + ivshmem['out_size']*idx + ivshmem['out_size']
        %>
        %if ivshmem['isvshmem_bundle']:
        /* IVSHMEM bundle regions (virtio-blk + virtio-console + virtio-net)*/
        /* IVSHMEM shared memory region (virtio-blk back-end) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},
            .size = 0x1000,   //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ,
        },
        {
            .phys_start = ${hex(start_addr + 0x1000)},
            .virt_start = ${hex(start_addr + 0x1000)},
            .size = 0xdf000,  //${readable_size(0xdf000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE,
        },
        { 0 },
        { 0 },
        <%
            start_addr = start_addr + 0x1000 + 0xdf000
        %>
        /* IVSHMEM shared memory region (virtio-con back-end) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},
            .size = 0x1000,  //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ,
        },
        {
            .phys_start = ${hex(start_addr + 0x1000)},
            .virt_start = ${hex(start_addr + 0x1000)},
            .size = 0xf000,   //${readable_size(0xf000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE,
        },
        { 0 },
        { 0 },
        <%
            start_addr = start_addr + 0x1000 + 0xf000
        %>
        /* IVSHMEM shared memory regions for 00:01.0 (networking) */
        {
            .phys_start = ${hex(start_addr)},
            .virt_start = ${hex(start_addr)},  
            .size = 0x1000,  //${readable_size(0x1000)}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED, 
        },
        { 0 },
        <%
            start_addr = start_addr + 0x1000
        %>
        %for idx in range(2):
        {
            .phys_start = ${hex(start_addr )},
            .virt_start = ${hex(start_addr )},
            .size = 0x7f000,  //${readable_size(0x7f000)}
            %if idx == ivshmem['id']:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_ROOTSHARED ,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_ROOTSHARED ,
            %endif
            <%
            start_addr = start_addr + 0x7f000
            %>
        },
        %endfor
        %endif 

        %endif

        /* system memory RAM */
        %for mem in root_sys_mems:
        {
            .phys_start = ${hex(mem['addr'])}, // ${readable_size(mem['addr'])}
            .virt_start = ${hex(mem['addr'])}, // ${readable_size(mem['addr'])}
            .size       = ${hex(mem['size'])}, // ${readable_size(mem['size'])}
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_EXECUTE,
        },
        %endfor

        /*****************/
        /* Devices
         *****************/
        %for dev in devices:
        /* ${dev['name']}   ${dev['compatible']}  */
        {
            .phys_start = ${hex(dev['addr'])},
            .virt_start = ${hex(dev['addr'])},
            .size       = ${hex(dev['size'])}, // ${readable_size(dev['size'])}
        %if  'uart' in dev['name'].lower():
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO_16 | JAILHOUSE_MEM_IO_32 |JAILHOUSE_MEM_IO_UNALIGNED,
        %elif ('gpio' in dev['name'].lower()) or ('adc' in dev['name'].lower() or not_4k_align(dev['size']) or  not_4k_align(dev['addr']) ):
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO_32 | JAILHOUSE_MEM_IO_UNALIGNED,
        %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO ,
        %endif
        },
        %endfor

        /*****************/
        /* Regions
         *****************/
        %for region in regions:
        /* ${region['name']} */
        {
            .phys_start = ${hex(region['addr'])},
            .virt_start = ${hex(region['addr'])},
            .size       = ${hex(region['size'])}, // ${readable_size(region['size'])}
            %if not_4k_align(region['addr']) or not_4k_align(region['size']):
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO | JAILHOUSE_MEM_IO_UNALIGNED,
            %else:
            .flags = JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE | JAILHOUSE_MEM_IO,
            %endif
        },
        %endfor
    },

    .irqchips = {
        /* GIC */
        %for idx in range(gic_info["gic_int_no_max"] // 128 +1):
        {
            .address = ${hex(gic_info["gicd_base"])},  
            .pin_base = ${idx * 128  +32 } ,
            .pin_bitmap = {
                0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
            }
        },
        %endfor
    },

    %if len(pci_devices) > 0 or ivshmem is not None:
    .pci_devices = {
        %if ivshmem is not None:
        {
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0,
            .bdf = 0 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 2,
            .shmem_regions_start = 0,
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = ${ivshmem['count']},
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_UNDEFINED,
        },
        %if ivshmem['isvshmem_bundle']:
        { /* IVSHMEM (virtio-blk back-end) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0,
            .bdf = 0x01 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 2,
            .shmem_regions_start = ${ivshmem['count'] + 2},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK +
                VIRTIO_DEV_BLOCK,
        },
        { /* IVSHMEM (virtio-con back-end) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0,
            .bdf = 0x02 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 3,
            .shmem_regions_start = ${ivshmem['count'] + 2 + 4},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VIRTIO_BACK +
                VIRTIO_DEV_CONSOLE,
        },
        { /* IVSHMEM (networking) */
            .type = JAILHOUSE_PCI_TYPE_IVSHMEM,
            .domain = 0x0000,
            .bdf = 0x03 << 3,
            .bar_mask = JAILHOUSE_IVSHMEM_BAR_MASK_MSIX,
            .num_msix_vectors = 2,
            .shmem_regions_start = ${ivshmem['count'] + 2 + 4 + 4},
            .shmem_dev_id = ${ivshmem['id']},
            .shmem_peers = 2,
            .shmem_protocol = JAILHOUSE_SHMEM_PROTO_VETH,
        },
        %endif
        %endif
    },
    %endif
};
